#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include "avl.h"

#define MAX_PRIME       8000
#define MAX_WORD_SIZE   100

void error(const char *message);
int ispalindrome(const char *word, int len);

int main(int argc, char *argv[])
{
    /* check for file argument */
    if(argc < 2) error("Missing input file.");

    /* open file and check if it exists */
    FILE *fp = fopen(argv[1], "r");
    if(fp == NULL) error("File does not exists.");

    /* retrieve file size */
    fseek(fp, 0, SEEK_END);
    long filesize = ftell(fp);

    /* allocate space to store file */
    char *buffer = (char *) malloc(filesize * sizeof(char));

    if(buffer == NULL) error("Out of memory.");

    /* copy file to memory and close it */
    rewind(fp);
    fread(buffer, sizeof(char), filesize, fp);
    fclose(fp);

    fprintf(stderr, "Calculating Sieve of Eratosthenes...\n");

    /* the vector isnotprime has 1 if the number is NOT prime and 0 otherwise */
    int *isnotprime = (int *) calloc(MAX_PRIME + 1, sizeof(int));

    if(isnotprime == NULL) error("Out of memory.");

    /* calculate Sieve of Eratosthenes up to MAX_PRIME */
    isnotprime[0] = 1;
    isnotprime[1] = 1;

    int i, j;
    for (i = 2; i <= MAX_PRIME; i++) {
        if(isnotprime[i]) continue; /* it was already marked */
        /* mark multiples */
        for(j = i * i; j <= MAX_PRIME ; j += i)
            isnotprime[j] = 1;
    }

    avl_t *avl = avl_create();
    char *word;
    int len;
    int sum;

    fprintf(stderr, "Processing words...\n");

    for(i = 0; i < filesize; i++)
    {
        /* ignore non alphanumeric characters */
        if(!isalnum(buffer[i])) continue;

        buffer[i] = tolower(buffer[i]);

        /* start a word */
        word = &buffer[i++];
        len = 1;
        sum = (int) word[0];

        /* find the end */
        while(isalnum(buffer[i]))
        {
            buffer[i] = tolower(buffer[i]);
            sum += (int) buffer[i];
            i++;
            len++;
        }
        /* end of word */
        buffer[i] = '\0';

        /* check if this word is a palindrome and is not repeated */
        if(len >= 3 && ispalindrome(word, len) && avl_insert(avl, word))
        {
            printf("%s - %d %s prime\n", word, sum,
                   isnotprime[sum] ? "is not" : "is");
        }
    }

    fprintf(stderr, "Finished!\n");

    avl_destroy(avl);
    free(buffer);
    free(isnotprime);

    return 0;
}

void error(const char *message)
{
    fprintf(stderr, "%s\n", message);
    exit(1);
}

int ispalindrome(const char *word, int len)
{
    int i, j;
    for(i = 0, j = len - 1; i <= j; i++, j--)
        if(word[i] != word[j])
            return 0;
    return 1;
}

